#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <semaphore.h>
#include <pthread.h>
#include <time.h>

class CMutex  
{
public:
  CMutex () { pthread_mutex_init (&m_mutex, NULL); }
  ~CMutex (){ pthread_mutex_destroy (&m_mutex); }
  int Lock     () { return pthread_mutex_lock    (&m_mutex); }
  int UnLock   () { return pthread_mutex_unlock  (&m_mutex); }
  int TryLock  () { return pthread_mutex_trylock (&m_mutex); }
  pthread_mutex_t *GetMutex () { return &m_mutex; }
private:
  pthread_mutex_t     m_mutex;
  //pthread_mutexattr_t m_mutexAttr;
};

class CSemaphore
{
public:
  CSemaphore (int initNum = 0) { sem_init (&m_sem, 0, initNum); }
  ~CSemaphore () {sem_destroy (&m_sem);}
  int  Wait ()   {sem_wait (&m_sem);}
  int  TryWait (){sem_trywait (&m_sem);}
  int  Post ()   {sem_post (&m_sem);;}
private:
  sem_t  m_sem;
};
class CCond
{
public:
  CCond () {pthread_cond_init (&m_cond, NULL);m_count = 0;}
  ~CCond () {pthread_cond_destroy (&m_cond);}
  int Wait_ ()
  {
    m_mutex.Lock ();
    if (m_count <= 0)
    {
	pthread_cond_wait (&m_cond, m_mutex.GetMutex());
    }
    m_count--;
    m_mutex.UnLock ();
    return 0;
  }
  void Signal_ ()
  {
    m_mutex.Lock ();
    m_count++;
    pthread_cond_signal (&m_cond);
    m_mutex.UnLock ();
  }
  int Wait ()
  {
    m_mutex.Lock ();
    pthread_cond_wait (&m_cond, m_mutex.GetMutex());
    m_mutex.UnLock ();
    return 0;
  }
  void Signal ()
  {
    m_mutex.Lock ();
    pthread_cond_signal (&m_cond);
    m_mutex.UnLock ();
  }
  pthread_cond_t m_cond;
  volatile size_t m_count;
  CMutex m_mutex;
};
CSemaphore g_sem;
CCond g_cond;
int handle_ready (int handle, int r_ready, int w_ready, int e_ready, int msec) 
{
    int width = handle + 1; //
    fd_set rset, wset, eset;

    g_cond.Wait ();
    printf ("start poll\n");
    // must define here and not define in while loop
    struct timeval tv;
    if (msec != -1)
    {
	tv.tv_sec   = msec / 1000;
	tv.tv_usec  = (msec % 1000) * 1000;
    }
    int ret_val = 0;
    while (1)
    {
	FD_ZERO (&rset);
	FD_SET (handle, &rset);
	ret_val = ::select (width, r_ready ? &rset : 0, 
		w_ready ? &(wset = rset) : 0, 
		e_ready ? &(eset = rset) : 0,
		msec == -1 ? 0 : &tv);
	    printf ("catch an signal\n");
	// not clear the fd_set return -1, POSIX 1.0v: timeval would be modify
	// clear all the fd_set return 0 (timeout)
	if ((ret_val == -1) && (errno == EINTR))// interupt by signal
	{
	    printf ("catch an signal\n");
	    continue;
	}
	break;  // timeout or ready
    }
    return ret_val;
}

void *sig (void *)
{
    g_cond.Signal ();
    sleep (3);
    //g_sem.Post ();
    g_cond.Signal ();
}
int main ()
{
    pthread_t pid;
    pthread_create (&pid, NULL, sig, NULL);
    int ret_val = handle_ready (2, 1, 0, 1, -1);
    if (ret_val < 0)
    {
	perror ("select");
    }
    pthread_join (pid, NULL);
    sleep (2);
    return 0;
}
